package practica1;


import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import javax.swing.*;
import org.apache.log4j.*;
import practica1.controller.Controller;
import practica1.preferences.PreferencesListener;
import practica1.preferences.PreferencesXML;
import practica1.ui.BarraEstado;
import practica1.ui.BarraMenus;
import practica1.ui.PanelExperimentos;
import practica1.ui.PanelPoblaciones;

/**
 * Clase que se encarga de inicializar el programa y construir la ventana principal.
 * @author Miguel González - Ceura
 */
public class Practica1 extends JFrame implements PreferencesListener {

    private PreferencesXML prefs;
    private JSplitPane splitPane;
    private PanelPoblaciones panelPoblaciones;
    private PanelExperimentos panelExperimentos;
    private BarraEstado panelBarraEstado;
    private static Practica1 practica1 = null;
    
    public final static Logger log = Logger.getLogger("Practica1Log");
    private final static String VERSION = "1.2";
    private int anchoSplit;
    
    /**
     * Método estático que se encarga de contruir la aplicación
     * @param args String[]
     */
    public static void main(String[] args) {
        
        //Creamos la carpeta para el log en el caso de que no exista
        File rutaLog = new File(System.getProperty("user.home") +
                "/.practica1");
        //Si no existe la ruta del log la creamos
        if(!rutaLog.exists()) {
            //Si no se puede crear la ruta
            if(!rutaLog.mkdirs()) {
                log.error("No se pudo crear la ruta donde se almacena"
                        + " el log del programa");
            }
        }
        
        
        //Configuramos el logger con los valores iniciales
        PropertyConfigurator.configure(Practica1.class.getResource(
            "log4j.properties"));
        //Agregamos un appender para guardar en un fichero de texto
        try {
            //Guardamos los ficheros por dia-mes-años
            PatternLayout patternLayout = new PatternLayout(
                    "[%-5p] %d{ISO8601} [%C][%t] - %m%n");
            Appender apenderScreen = new FileAppender(patternLayout, 
                rutaLog.getAbsolutePath() + "/" + Calendar.getInstance()
                    .get(Calendar.DAY_OF_MONTH) + "-" + Calendar.getInstance()
                    .get(Calendar.MONTH) + "-" + Calendar.getInstance()
                    .get(Calendar.YEAR), true);
            log.addAppender(apenderScreen);
        } catch(IOException ex) {
            log.error("Error creando fichero log", ex);
        }

        log.info("Inicializada aplicación (Versión " + VERSION + ")");
        
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run() {
                practica1 = new Practica1();
                practica1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            }
        });
    }

    /**
     * Constructor de la práctica de acceso privado, se encarga de contruir
     * los componentes.
     */
    private Practica1() {
        //Obtenemos las preferencias de esta clase
        prefs = PreferencesXML.getInstance();
        
        init();
    }
    
    /**
     * Devuelve la instancia de la clase
     * @return Practica1 Devuelve el objeto de la práctica
     */
    public static Practica1 getInstance() {
        return practica1;
    }
    
    /**
     * Método que se encarga de inicializar los componentes de la aplicación
     * de forma ordenada.
     */
    private void init() {
        addWindowListener(new EscuchadorVentana());
        prefs.addPreferencesListener(this);

        //Restauramos las preferencias del usuario
        restorePreferences();
        
        //Inicializamos los componentes
        initComponents();
        
        //Ponemos finalmente visible el formulario
        setVisible(true);
        
        //Restauramos las preferencias del controlador una vez se ha cargado
        //toda la parte SWING
        Controller.getInstance().restorePreferences();
    }
    
    /**
     * Construye los componentes gráficos (barra de menú, paneles...)
     */
    private void initComponents() {
        BarraMenus menuBar = new BarraMenus();
        setJMenuBar(menuBar);
        
        Container containerPane = getContentPane();
        containerPane.setLayout(new BorderLayout());
        
        panelPoblaciones = new PanelPoblaciones();
        panelExperimentos = new PanelExperimentos();
        panelBarraEstado = new BarraEstado();
        
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 
                panelExperimentos, panelPoblaciones);
        splitPane.setDividerLocation(anchoSplit);
        
        containerPane.add(splitPane, BorderLayout.CENTER);
        containerPane.add(panelBarraEstado, BorderLayout.SOUTH);
    }
    
    /**
     * Método que es llamada al cerrarse la aplicación y se encarga de guardar
     * las preferencias de como se encuentra la ventana.
     */
    @Override
    public void savePreferences() {
        //Guardamos el tamaño y posición de la ventana
        prefs.setValue(this, "x", Integer.toString(getX()));
        prefs.setValue(this, "y", Integer.toString(getY()));
        prefs.setValue(this, "width", Integer.toString(getWidth()));
        prefs.setValue(this, "height", Integer.toString(getHeight()));
        prefs.setValue(this, "split-width", Integer.toString(
                splitPane.getDividerLocation()));
    }
    
    /**
     * Método que restaura las preferencias de la ventana (anchura, altura, 
     * posición, etc. Y que e llamado al cargarse la aplicación.
     */
    private void restorePreferences() {
        //Restauramos el tamaño y posición de la ventana
        String x = prefs.getValue(this, "x", "100");
        String y = prefs.getValue(this, "y", "100");
        String width = prefs.getValue(this, "width", "500");
        String height = prefs.getValue(this, "height", "400");
        setBounds(Integer.parseInt(x), Integer.parseInt(y), Integer.parseInt(width),
                Integer.parseInt(height));
        anchoSplit = Integer.parseInt(
                prefs.getValue(this, "split-width","200"));
        try {
            UIManager.setLookAndFeel(
                        prefs.getValue(this, "apariencia", 
                    UIManager.getSystemLookAndFeelClassName()));
            SwingUtilities.updateComponentTreeUI(this);
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Practica1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Practica1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Practica1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Practica1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Clase privada que se encarga de controlar los eventos que sucedan
     * con el formulario
     */
    private class EscuchadorVentana extends WindowAdapter {
        
        /**
         * Al cerrar la ventana guardamos primero sus preferencias
         * @param e WindowEvent Evento de ventana producido
         */
        @Override
        public void windowClosing(WindowEvent e) {
            Controller.getInstance().salirAplicacion();
        }
    }
}
